package org.lql.chaos.web.handler;

import lombok.extern.slf4j.Slf4j;
import org.lql.chaos.common.constant.ErrorCode;
import org.lql.chaos.common.exception.BizException;
import org.lql.chaos.common.exception.SystemException;
import org.lql.chaos.common.response.ErrorResponse;
import org.springframework.beans.TypeMismatchException;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.jdbc.CannotGetJdbcConnectionException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingPathVariableException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.client.RestClientException;

import javax.servlet.http.HttpServletRequest;
import java.util.stream.Collectors;

/**
 * @author: liangqinglong
 * @date: 2025-07-02 10:25
 * @description: 全局异常处理器
 * {@code @RestControllerAdvice} 是 Spring MVC 中的一个注解，用于标记一个类为全局异常处理器。
 * {@Code @ExceptionHandler(XxxException.class)} 是一个异常处理方法，用于处理指定类型的异常。
 * {@code ErrorResponse} 响应结构体，统一异常处理返回结构体
 * {@code ErrorCode} 错误码枚举，具体划分有待商榷
 **/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

	// ========= 1. 参数校验 =========

	@ExceptionHandler(MethodArgumentNotValidException.class)
	public ErrorResponse handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpServletRequest request) {
		String msg = ex.getBindingResult().getFieldErrors()
				.stream().map(DefaultMessageSourceResolvable::getDefaultMessage)
				.collect(Collectors.joining("; "));
		log.warn("[参数校验异常] {} {}", msg, ex.getMessage(), ex);
		return ErrorResponse.of(ErrorCode.CUSTOM_ERROR, msg, ex.getClass().getName(), request.getRequestURI());
	}

	@ExceptionHandler(BindException.class)
	public ErrorResponse handleBindException(BindException ex, HttpServletRequest request) {
		String msg = ex.getFieldErrors().stream()
				.map(FieldError::getDefaultMessage)
				.collect(Collectors.joining("; "));
		log.warn("[参数绑定异常] {} {}", msg, ex.getMessage(), ex);
		return ErrorResponse.of(ErrorCode.CUSTOM_ERROR, msg, ex.getClass().getName(), request.getRequestURI());
	}

	@ExceptionHandler(MissingServletRequestParameterException.class)
	public ErrorResponse handleMissingParam(MissingServletRequestParameterException ex, HttpServletRequest request) {
		log.warn("[缺少请求参数异常] {} {}", ex.getMessage(), ex.getClass().getName(), ex);
		return ErrorResponse.of(ErrorCode.CUSTOM_ERROR, "请求参数", ex.getClass().getName(), request.getRequestURI());
	}

	@ExceptionHandler(MissingPathVariableException.class)
	public ErrorResponse handleMissingPathVar(MissingPathVariableException ex, HttpServletRequest request) {
		log.warn("[缺少必要路径异常] {} {}", ex.getMessage(), ex.getClass().getName(), ex);
		return ErrorResponse.of(ErrorCode.CUSTOM_ERROR, "请求路径", ex.getClass().getName(), request.getRequestURI());
	}

	// ========= 2. 类型转换 / JSON格式错误 =========

	@ExceptionHandler(HttpMessageNotReadableException.class)
	public ErrorResponse handleMessageNotReadable(HttpMessageNotReadableException ex, HttpServletRequest request) {
		log.warn("[参数转换异常] {} {}", ex.getMessage(), ex.getClass().getName(), ex);
		return ErrorResponse.of(ErrorCode.CUSTOM_ERROR, "JSON 格式", ex.getClass().getName(), request.getRequestURI());
	}

	@ExceptionHandler(TypeMismatchException.class)
	public ErrorResponse handleTypeMismatch(TypeMismatchException ex, HttpServletRequest request) {
		log.warn("[类型不匹配异常] {} {}", ex.getMessage(), ex.getClass().getName(), ex);
		return ErrorResponse.of(ErrorCode.CUSTOM_ERROR, "类型不匹配", ex.getClass().getName(), request.getRequestURI());
	}

	// ========= 3. 请求方式错误 =========

	@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
	public ErrorResponse handleMethodNotSupported(HttpRequestMethodNotSupportedException ex, HttpServletRequest request) {
		log.warn("[请求方式错误异常] {} {}", ex.getMessage(), ex.getClass().getName(), ex);
		return ErrorResponse.of(ErrorCode.CUSTOM_ERROR, "不支持的请求方式", ex.getClass().getName(), request.getRequestURI());
	}

	// ========= 4. 权限 / 认证 =========

	@ExceptionHandler(AccessDeniedException.class)
	public ErrorResponse handleAccessDenied(AccessDeniedException ex, HttpServletRequest request) {
		log.warn("[权限不足异常] {} {}", ex.getMessage(), ex.getClass().getName(), ex);
		return ErrorResponse.of(ErrorCode.CUSTOM_ERROR, "无访问权限", ex.getClass().getName(), request.getRequestURI());
	}

	@ExceptionHandler(AuthenticationException.class)
	public ErrorResponse handleAuthentication(AuthenticationException ex, HttpServletRequest request) {
		log.warn("[认证异常] {} {}", ex.getMessage(), ex.getClass().getName(), ex);
		return ErrorResponse.of(ErrorCode.CUSTOM_ERROR, "用户未登录或身份失效", ex.getClass().getName(), request.getRequestURI());
	}

	// ========= 5. 业务异常 =========

	@ExceptionHandler(BizException.class)
	public ErrorResponse handleBizException(BizException ex, HttpServletRequest request) {
		ErrorCode code = ex.getErrorCode();
		log.warn("[业务异常] {} - {}", code.getCode(), ex.getMessage());
		return ErrorResponse.of(code, "业务异常", ex.getClass().getName(), request.getRequestURI());
	}

	// ========= 6. 系统异常 =========

	@ExceptionHandler(SystemException.class)
	public ErrorResponse handleSystemException(SystemException ex, HttpServletRequest request) {
		ErrorCode code = ex.getErrorCode();
		log.error("[系统异常] {} - {}", code.getCode(), ex.getMessage(), ex);
		return ErrorResponse.of(ErrorCode.CUSTOM_ERROR, "系统异常", ex.getClass().getName(), request.getRequestURI());
	}

	// ========= 7. 数据库异常 =========

	@ExceptionHandler(CannotGetJdbcConnectionException.class)
	public ErrorResponse handleDbConnection(CannotGetJdbcConnectionException ex, HttpServletRequest request) {
		log.error("[数据库异常] {} - {}", ex.getMessage(), ex.getClass().getName(), ex);
		return ErrorResponse.of(ErrorCode.CUSTOM_ERROR, "请检查数据库服务", ex.getClass().getName(), request.getRequestURI());
	}

	@ExceptionHandler(BadSqlGrammarException.class)
	public ErrorResponse handleSqlGrammar(BadSqlGrammarException ex, HttpServletRequest request) {
		log.error("[数据库异常] {} - {}", ex.getMessage(), ex.getClass().getName(), ex);
		return ErrorResponse.of(ErrorCode.CUSTOM_ERROR, "SQL语法错误,请联系开发修复", ex.getClass().getName(), request.getRequestURI());
	}

	// ========= 8. 网络/远程服务异常 =========

	@ExceptionHandler(RestClientException.class)
	public ErrorResponse handleRestClient(RestClientException ex, HttpServletRequest request) {
		log.error("[网络异常] {} - {}", ex.getMessage(), ex.getClass().getName(), ex);
		return ErrorResponse.of(ErrorCode.CUSTOM_ERROR, "远程调用失败", ex.getClass().getName(), request.getRequestURI());
	}

	// ========= 9. 未知异常（兜底）=========

	@ExceptionHandler(Exception.class)
	public ErrorResponse handleUnknown(Exception ex, HttpServletRequest request) {
		log.error("【未知异常】", ex);
		return ErrorResponse.of(ErrorCode.CUSTOM_ERROR, "未知异常", ex.getClass().getName(), request.getRequestURI());
	}

}
